﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;

using DKIM;

using CloudSoft.Extensions;
using System.Threading;

namespace ERPStore.NewsLetters.MessageReaders
{
	public class SendNewsLetterMessageReader : Ariane.MessageReaderBase<ERPStore.NewsLetters.Models.PendingItem>
	{
		private int m_Pool;
		private System.Threading.ManualResetEvent m_WaitingFreeThread;

		public SendNewsLetterMessageReader(ERPStore.NewsLetters.Services.NewsLettersService newsLetterService
			, ERPStore.Services.IServiceBus bus
			, ERPStore.Logging.ILogger logger
			)
		{
			this.NewsLetterService = newsLetterService;
			this.Bus = bus;
			this.m_Pool = 0;
			m_WaitingFreeThread = new System.Threading.ManualResetEvent(false);
			this.Logger = logger;
		}

		protected ERPStore.NewsLetters.Services.NewsLettersService NewsLetterService { get; private set; }
		protected ERPStore.Services.IServiceBus Bus { get; private set; }
		protected ERPStore.Logging.ILogger Logger { get; private set; }

		public override void ProcessMessage(ERPStore.NewsLetters.Models.PendingItem pendingItem)
		{
			Logger.Debug("newsletters sending for recipient {0}", pendingItem.EmailRecipientId);

			var callBack = new System.Threading.WaitCallback((state) =>
			{
				string reason = null;
				var p = state as ERPStore.NewsLetters.Models.PendingItem;
				try
				{
					if (p != null)
					{
						SendEmail(p);
					}
				}
				catch (Exception ex)
				{
					reason = ex.Message;
				}
				finally
				{
					Bus.Send(Queues.QUEUE_SENT, new ERPStore.NewsLetters.Events.NewsLetterSentEventMessage()
					{
						CampaignId = p.CampaignId,
						EmailRecipientId = p.EmailRecipientId,
						FaultReason = reason,
					});

					Interlocked.Decrement(ref m_Pool);
					Logger.Debug("Threadpool count :{0}", m_Pool);
					if (m_Pool < 1)
					{
						m_WaitingFreeThread.Set();
					}
				}
			});

			if (m_Pool > 5)
			{
				m_WaitingFreeThread.WaitOne();
			}

			Interlocked.Increment(ref m_Pool);
			System.Threading.ThreadPool.QueueUserWorkItem(callBack, pendingItem);
			m_WaitingFreeThread.Reset();
		}

		private void SendEmail(ERPStore.NewsLetters.Models.PendingItem pendingItem)
		{
			var campaign = NewsLetterService.GetCampaignById(pendingItem.CampaignId);
			var newsLetter = NewsLetterService.GetNewsLetterById(campaign.NewsLetterId);
			var smtpServer = NewsLetterService.GetSMTPServerById(campaign.SMTPServerId);

			var recipient = NewsLetterService.GetEmailRecipientById(pendingItem.EmailRecipientId);
			if (recipient.IsBlackListed)
			{
				return;
			}

			Logger.Debug("Newsletters Service Sending message {0} to {1}", pendingItem.MailMessage.Subject, pendingItem.MailMessage.Recipients[0].Address);

			if (ERPStore.GlobalConfiguration.Configuration.ExecutingContext == ERPStore.Models.ExecutingContext.Production)
			{
				if (smtpServer.DeliveryMethod == "WebApi")
				{
					NewsLetterService.SendMessageWithWebApi(smtpServer, pendingItem.MailMessage);
				}
				else
				{
					var message = (System.Net.Mail.MailMessage)pendingItem.MailMessage;
					SendMessage(smtpServer, message, pendingItem);
				}
			}
		}

		private void SendMessage(ERPStore.NewsLetters.Models.SMTPSettings smtpServer, MailMessage message, ERPStore.NewsLetters.Models.PendingItem pendingItem)
		{
			if (!smtpServer.DKIMPrivateKey.IsNullOrEmpty())
			{
				AddDkimHeaders(message, smtpServer);
			}

			var htmlView = AlternateView.CreateAlternateViewFromString(message.Body, null, "text/html");
			htmlView.TransferEncoding = System.Net.Mime.TransferEncoding.QuotedPrintable;
			message.AlternateViews.Add(htmlView);

			using (var sender = GetSmtpClient(smtpServer))
			{
				sender.Send(message);
			}
		}

		System.Net.Mail.SmtpClient GetSmtpClient(ERPStore.NewsLetters.Models.SMTPSettings smtpServer)
		{
			var sender = new System.Net.Mail.SmtpClient();
			if (smtpServer.DeliveryMethod == "Directory")
			{
				var path = System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location);
				path = System.IO.Path.Combine(path, "emails");
				if (!System.IO.Directory.Exists(path))
				{
					System.IO.Directory.CreateDirectory(path);
				}
				sender.PickupDirectoryLocation = path;
				sender.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
			}
			else
			{
				sender.EnableSsl = smtpServer.UseSSL;
				sender.Host = smtpServer.HostName;
				sender.Port = smtpServer.Port;
				sender.Timeout = Math.Max(1000 * 100, smtpServer.Timeout);
				if (!smtpServer.Login.IsNullOrEmpty())
				{
					sender.Credentials = new System.Net.NetworkCredential(smtpServer.Login, smtpServer.Password);
				}
			}
			sender.SendCompleted += new System.Net.Mail.SendCompletedEventHandler(sender_SendCompleted);
			return sender;
		}

		void sender_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
		{
			if (!e.Cancelled)
			{
				return;
			}

			if (e.Error == null)
			{
				return;
			}

			var pendingItem = e.UserState as ERPStore.NewsLetters.Models.PendingItem;
			if (pendingItem == null)
			{
				return;
			}

			try
			{
				var lastSentItem = NewsLetterService.GetLastEmailSentByRecipientId(pendingItem.EmailRecipientId);
				if (lastSentItem == null)
				{
					return;
				}
				lastSentItem.FaultReason = e.Error.ToString();
				NewsLetterService.SaveEmailSent(lastSentItem);
			}
			catch (Exception ex)
			{
				Logger.Error(ex);
			}
		}

		private void AddDkimHeaders(System.Net.Mail.MailMessage message, ERPStore.NewsLetters.Models.SMTPSettings smtpServer)
		{
			try
			{
				var privateKey = DKIM.PrivateKeySigner.Create(smtpServer.DKIMPrivateKey);
				var headerToSign = new string[] { "From", "To", "Subject" };
				var domainKeySigner = new DKIM.DomainKeySigner(privateKey, smtpServer.DKIMDomain, smtpServer.DKIMSelector, headerToSign);

				message.DomainKeySign(domainKeySigner);

				var dkimSigner = new DkimSigner(privateKey, smtpServer.DKIMDomain, smtpServer.DKIMSelector, headerToSign);
				message.DkimSign(dkimSigner);
			}
			catch (Exception ex)
			{
				Logger.Error(ex);
			}
		}

		private void AttachInternalImage(System.Net.Mail.MailMessage mailMessage)
		{
			string imagePattern = @"(src=[\""|']{0,1}(?<src>\w:\\[^\""|\s]*)[[\""|']{0,1}|\s*]|src=[\""|']{0,1}(?<prefix>file:///)(?<src>\w:/[^\""|\s]*)[[\""|']{0,1}|\s*])";
			imagePattern = @"src=[\""|']{0,1}/newsletters(?<src>[^\""|\s]*)[[\""|']{0,1}|\s*]";
			var exp = new System.Text.RegularExpressions.Regex(imagePattern, System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
			System.Text.RegularExpressions.Match m;
			var imageList = new List<LinkedResource>();

			var virtualFilePath = ERPStore.NewsLetters.Configuration.ConfigurationSettings.AppSettings["virtualFilePath"];
			var physicalPath = ERPStore.GlobalConfiguration.Configuration.Settings.PhysicalPath;
			physicalPath = System.IO.Path.Combine(physicalPath, virtualFilePath.Replace("~/", "").Replace("/", @"\"));

			for (m = exp.Match(mailMessage.Body); m.Success; m = m.NextMatch())
			{
				if (m.Value.Length == 0)
				{
					continue;
				}
				var originalsrc = m.Groups["src"].Value;
				if (originalsrc.IsNullOrEmpty())
				{
					continue;
				}
				// originalsrc = originalsrc.Replace("newsletters", "");
				var src = System.IO.Path.Combine(physicalPath, originalsrc.Replace('/', '\\').TrimStart('\\'));
				var ext = System.IO.Path.GetExtension(src).Replace(".", "").ToLower();
				var mimeType = ERPStore.Extensions.MimeExtensions.MIMETypeDictionary.FirstOrDefault(i => i.Key.Equals(ext));
				var img = new LinkedResource(src, mimeType.Value);
				var id = Guid.NewGuid().ToString().Substring(0, 8) + "." + ext;
				img.ContentId = id;
				imageList.Add(img);
				mailMessage.Body = mailMessage.Body.Replace("/newsletters" + originalsrc, string.Format("cid:{0}", id));
			}

			var htmlView = AlternateView.CreateAlternateViewFromString(mailMessage.Body, null, "text/html");
			foreach (var lr in imageList)
			{
				htmlView.LinkedResources.Add(lr);
			}
			htmlView.TransferEncoding = System.Net.Mime.TransferEncoding.QuotedPrintable;

			mailMessage.AlternateViews.Add(htmlView);
		}



	}
}
